<h1 id="linux-驱动准备">Linux 驱动准备</h1>
<!-- vim-markdown-toc GFM -->
<ul>
<li><a href="#io体系结构">I/O体系结构</a></li>
<li><a href="#硬件设备连接到系统">硬件设备连接到系统</a>
<ul>
<li><a href="#硬件层面的连接">硬件层面的连接</a></li>
<li><a href="#与外设通信">与外设通信</a></li>
</ul></li>
<li><a href="#设备数据库">设备数据库</a>
<ul>
<li><a href="#通用数据库数据结构">通用数据库数据结构</a></li>
<li><a href="#kobj_map函数">kobj_map函数</a></li>
<li><a href="#字符设备相关的数据库数据结构">字符设备相关的数据库数据结构</a></li>
</ul></li>
<li><a href="#kobj">kobj</a>
<ul>
<li><a href="#kobject">kobject</a></li>
<li><a href="#kset">kset</a></li>
<li><a href="#kobj_type">kobj_type</a></li>
<li><a href="#kobject相关的函数">kobject相关的函数</a></li>
</ul></li>
</ul>
<!-- vim-markdown-toc -->
<h2 id="io体系结构">I/O体系结构</h2>
<p>处理外设IO的时候必须考虑的三个问题：</p>
<ol type="1">
<li><p>如何对硬件设备进行寻址？（我怎么才能找到设备？）</p></li>
<li><p>如何设计上层与设备交互的方法？</p></li>
<li><p>如何管理并上报这些硬件设备？</p></li>
</ol>
<p>与外设的通信是一种层次化的通信</p>
<figure>
<img src="/home/wu/code/learning/pictures/IO_layer_19_11_23_1.png" alt="" /><figcaption>IO_layer</figcaption>
</figure>
<p>看得出来，与外设的通信是通过VFS层进行的。那么肯定需要支持一堆VFS的操作 比如打开关闭之类的操作。</p>
<p>这个设计方案回答了一部分上面三个问题中的2和3。应用程序可以通过VFS提供的标准操作来与硬件设备进行交互而从最终用户的角度来说管理这些特殊的文件就可以管理（至少是内核允许的用户层管理）这些硬件。</p>
<h2 id="硬件设备连接到系统">硬件设备连接到系统</h2>
<h3 id="硬件层面的连接">硬件层面的连接</h3>
<p>主要靠总线，就目前而言外设主要靠PCI总线而内存靠内存总线。</p>
<h3 id="与外设通信">与外设通信</h3>
<p>有如下几种交互的方式：</p>
<ol type="1">
<li><p>I/O端口: 处理器维持了一个独立的虚拟地址空间（CPU的物理地址线也有一部分被占用），通过特殊的IO指令与外设交互。</p></li>
<li><p>I/O内存映射：CPU提供了这样的功能，将内存区映射到外设的端口上（GPU应该这样），内核就可以通过通用的一些指令来处理这些外设。PCI总线也会这样搞，这肯定需要内核提供内存。内核除了支持PCI这样弄之外还提供了抽象层对I/O映射进行处理。</p></li>
<li><p>轮询与中断：这没啥可说的</p></li>
<li><p>通过总线控制设备的访问：总线控制设备肯定提供了很多高级的功能诸如设备描述表之类的东西来描述连接到总线上的设备。通过总线控制设备与设备交互肯定更加方便。</p></li>
</ol>
<h2 id="设备数据库">设备数据库</h2>
<p>内核如何快速知道目前有那些字符与块设备？当然需要建立一个数据库。 可以想到内核使用了散列表来处理快速这一需求，通过若干的指针寻找到要找的设备，所以这一块比较无聊。</p>
<h3 id="通用数据库数据结构">通用数据库数据结构</h3>
<p>内核使用cdev_map来表示字符设备的散列表，bdev_map表示块设备的散列表。内核对这俩的定义是这样的。</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1"></a><span class="co">//static 说明你不能随便乱搞这些数据结构而只能通过接口</span></span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="dt">static</span> <span class="kw">struct</span> kobj_map *cdev_map;</span>
<span id="cb1-3"><a href="#cb1-3"></a></span>
<span id="cb1-4"><a href="#cb1-4"></a><span class="dt">static</span> <span class="kw">struct</span> kobj_map *bdev_map;</span></code></pre></div>
<p>看来是kobj_map数据结构的指针，指向的东西搞了半天是个高级数组。 想象一下kobj_map肯定包括指向的设备，主设备号被拉去做散列，那么次设备号就被写在结构体里面了。</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">struct</span> kobj_map {</span>
<span id="cb2-2"><a href="#cb2-2"></a>    <span class="kw">struct</span> probe {</span>
<span id="cb2-3"><a href="#cb2-3"></a>        <span class="co">//形成单链表</span></span>
<span id="cb2-4"><a href="#cb2-4"></a>        <span class="kw">struct</span> probe *next;</span>
<span id="cb2-5"><a href="#cb2-5"></a>        <span class="co">//意外，主次设备号全写进来了</span></span>
<span id="cb2-6"><a href="#cb2-6"></a>        dev_t dev;</span>
<span id="cb2-7"><a href="#cb2-7"></a>        <span class="co">//从设备号的范围。难道通过这个还可以处理到从设备？</span></span>
<span id="cb2-8"><a href="#cb2-8"></a>        <span class="dt">unsigned</span> <span class="dt">long</span> range;</span>
<span id="cb2-9"><a href="#cb2-9"></a>        <span class="co">//设备驱动模块</span></span>
<span id="cb2-10"><a href="#cb2-10"></a>        <span class="kw">struct</span> module *owner;</span>
<span id="cb2-11"><a href="#cb2-11"></a>        kobj_probe_t *get;</span>
<span id="cb2-12"><a href="#cb2-12"></a>        <span class="dt">int</span> (*lock)(dev_t, <span class="dt">void</span> *);</span>
<span id="cb2-13"><a href="#cb2-13"></a>        <span class="co">//其实就是指向了各自设备对应的结构体</span></span>
<span id="cb2-14"><a href="#cb2-14"></a>        <span class="dt">void</span> *data;</span>
<span id="cb2-15"><a href="#cb2-15"></a>    } *probes[<span class="dv">255</span>];<span class="co">//主设备号%255就是散列算法。。。。。。</span></span>
<span id="cb2-16"><a href="#cb2-16"></a>    <span class="co">//锁子，锁住了整个散列表</span></span>
<span id="cb2-17"><a href="#cb2-17"></a>    <span class="kw">struct</span> mutex *lock;</span>
<span id="cb2-18"><a href="#cb2-18"></a>};</span></code></pre></div>
<h3 id="kobj_map函数">kobj_map函数</h3>
<p>这个函数就是注册一下设备号以及设备号与实体的关联。</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a></span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="dt">int</span> kobj_map(<span class="kw">struct</span> kobj_map *domain, dev_t dev, <span class="dt">unsigned</span> <span class="dt">long</span> range,</span>
<span id="cb3-3"><a href="#cb3-3"></a>         <span class="kw">struct</span> module *module, kobj_probe_t *probe,</span>
<span id="cb3-4"><a href="#cb3-4"></a>         <span class="dt">int</span> (*lock)(dev_t, <span class="dt">void</span> *), <span class="dt">void</span> *data)</span>
<span id="cb3-5"><a href="#cb3-5"></a>{</span>
<span id="cb3-6"><a href="#cb3-6"></a>    <span class="dt">unsigned</span> n = MAJOR(dev + range - <span class="dv">1</span>) - MAJOR(dev) + <span class="dv">1</span>;</span>
<span id="cb3-7"><a href="#cb3-7"></a>    <span class="dt">unsigned</span> index = MAJOR(dev);</span>
<span id="cb3-8"><a href="#cb3-8"></a>    <span class="dt">unsigned</span> i;</span>
<span id="cb3-9"><a href="#cb3-9"></a>    <span class="kw">struct</span> probe *p;</span>
<span id="cb3-10"><a href="#cb3-10"></a></span>
<span id="cb3-11"><a href="#cb3-11"></a>    <span class="cf">if</span> (n &gt; <span class="dv">255</span>)</span>
<span id="cb3-12"><a href="#cb3-12"></a>        n = <span class="dv">255</span>;</span>
<span id="cb3-13"><a href="#cb3-13"></a></span>
<span id="cb3-14"><a href="#cb3-14"></a>    p = kmalloc(<span class="kw">sizeof</span>(<span class="kw">struct</span> probe) * n, GFP_KERNEL);</span>
<span id="cb3-15"><a href="#cb3-15"></a></span>
<span id="cb3-16"><a href="#cb3-16"></a>    <span class="cf">if</span> (p == NULL)</span>
<span id="cb3-17"><a href="#cb3-17"></a>        <span class="cf">return</span> -ENOMEM;</span>
<span id="cb3-18"><a href="#cb3-18"></a></span>
<span id="cb3-19"><a href="#cb3-19"></a>    <span class="cf">for</span> (i = <span class="dv">0</span>; i &lt; n; i++, p++) {</span>
<span id="cb3-20"><a href="#cb3-20"></a>        p-&gt;owner = module;</span>
<span id="cb3-21"><a href="#cb3-21"></a>        p-&gt;get = probe;</span>
<span id="cb3-22"><a href="#cb3-22"></a>        p-&gt;lock = lock;</span>
<span id="cb3-23"><a href="#cb3-23"></a>        p-&gt;dev = dev;</span>
<span id="cb3-24"><a href="#cb3-24"></a>        p-&gt;range = range;</span>
<span id="cb3-25"><a href="#cb3-25"></a>        p-&gt;data = data;</span>
<span id="cb3-26"><a href="#cb3-26"></a>    }</span>
<span id="cb3-27"><a href="#cb3-27"></a>    mutex_lock(domain-&gt;lock);</span>
<span id="cb3-28"><a href="#cb3-28"></a>    <span class="co">//串表</span></span>
<span id="cb3-29"><a href="#cb3-29"></a>    <span class="cf">for</span> (i = <span class="dv">0</span>, p -= n; i &lt; n; i++, p++, index++) {</span>
<span id="cb3-30"><a href="#cb3-30"></a>        <span class="kw">struct</span> probe **s = &amp;domain-&gt;probes[index % <span class="dv">255</span>];</span>
<span id="cb3-31"><a href="#cb3-31"></a>        <span class="cf">while</span> (*s &amp;&amp; (*s)-&gt;range &lt; range)</span>
<span id="cb3-32"><a href="#cb3-32"></a>            s = &amp;(*s)-&gt;next;</span>
<span id="cb3-33"><a href="#cb3-33"></a>        p-&gt;next = *s;</span>
<span id="cb3-34"><a href="#cb3-34"></a>        *s = p;</span>
<span id="cb3-35"><a href="#cb3-35"></a>    }</span>
<span id="cb3-36"><a href="#cb3-36"></a>    mutex_unlock(domain-&gt;lock);</span>
<span id="cb3-37"><a href="#cb3-37"></a>    <span class="cf">return</span> <span class="dv">0</span>;</span>
<span id="cb3-38"><a href="#cb3-38"></a>}</span>
<span id="cb3-39"><a href="#cb3-39"></a></span></code></pre></div>
<h3 id="字符设备相关的数据库数据结构">字符设备相关的数据库数据结构</h3>
<p>除了上面的那个散列表之外，为了管理字符设备的从设备号范围。内核增加了一个数据库：char_device_struct</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1"></a><span class="dt">static</span> <span class="kw">struct</span> char_device_struct {</span>
<span id="cb4-2"><a href="#cb4-2"></a>    <span class="co">//形成链表</span></span>
<span id="cb4-3"><a href="#cb4-3"></a>    <span class="kw">struct</span> char_device_struct *next;</span>
<span id="cb4-4"><a href="#cb4-4"></a>    <span class="dt">unsigned</span> <span class="dt">int</span> major;</span>
<span id="cb4-5"><a href="#cb4-5"></a>    <span class="co">//最小从设备号</span></span>
<span id="cb4-6"><a href="#cb4-6"></a>    <span class="dt">unsigned</span> <span class="dt">int</span> baseminor;</span>
<span id="cb4-7"><a href="#cb4-7"></a>    <span class="co">//多少个从设备号</span></span>
<span id="cb4-8"><a href="#cb4-8"></a>    <span class="dt">int</span> minorct;</span>
<span id="cb4-9"><a href="#cb4-9"></a>    <span class="dt">char</span> name[<span class="dv">64</span>];</span>
<span id="cb4-10"><a href="#cb4-10"></a>    <span class="kw">struct</span> cdev *cdev;      <span class="co">/* will die: 如果这个结构体也能找到字符设备的结构体，那么不就和kobj_map散列表的功能重了？所以will die*/</span> </span>
<span id="cb4-11"><a href="#cb4-11"></a>} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];</span></code></pre></div>
<p>对于数据库的操作很直接，所以不加赘述。块设备没有第二个数据库所以略过不表。</p>
<h2 id="kobj">kobj</h2>
<p>驱动相关的内核代码中出现了很多kobject、kset之类的东西。我们来解析一下这个东西是用来干啥的。</p>
<p>内核的驱动层存在大量的对象，为了方便管理这些对象并抽象一些可能共同存在的属性或者操作或者接口，有必要建立一个专门的kobject。</p>
<p>内核不仅仅是在驱动层使用了kobject，在其他目录下也有。</p>
<h3 id="kobject">kobject</h3>
<div class="sourceCode" id="cb5"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1"></a></span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="kw">struct</span> kobject {</span>
<span id="cb5-3"><a href="#cb5-3"></a>    <span class="co">//对象的名字，导出到sys文件系统可用此</span></span>
<span id="cb5-4"><a href="#cb5-4"></a>    <span class="dt">const</span> <span class="dt">char</span>      *name;</span>
<span id="cb5-5"><a href="#cb5-5"></a>    <span class="co">//引用计数，只有一个atomic_t类型的成员用来计数</span></span>
<span id="cb5-6"><a href="#cb5-6"></a>    <span class="kw">struct</span> kref     kref;</span>
<span id="cb5-7"><a href="#cb5-7"></a>    <span class="co">//链表</span></span>
<span id="cb5-8"><a href="#cb5-8"></a>    <span class="kw">struct</span> list_head    entry;</span>
<span id="cb5-9"><a href="#cb5-9"></a>    <span class="co">//父kobject</span></span>
<span id="cb5-10"><a href="#cb5-10"></a>    <span class="kw">struct</span> kobject      *parent;</span>
<span id="cb5-11"><a href="#cb5-11"></a>    <span class="co">//所属的kset</span></span>
<span id="cb5-12"><a href="#cb5-12"></a>    <span class="kw">struct</span> kset     *kset;</span>
<span id="cb5-13"><a href="#cb5-13"></a>    <span class="co">//与此kobject相关联的类型以及操作函数指针等，不同的kobject可能共用ktype所以是个指针</span></span>
<span id="cb5-14"><a href="#cb5-14"></a>    <span class="kw">struct</span> kobj_type    *ktype;</span>
<span id="cb5-15"><a href="#cb5-15"></a>    <span class="co">//关联的sysfs</span></span>
<span id="cb5-16"><a href="#cb5-16"></a>    <span class="kw">struct</span> sysfs_dirent *sd;</span>
<span id="cb5-17"><a href="#cb5-17"></a>    <span class="co">//是否注册了</span></span>
<span id="cb5-18"><a href="#cb5-18"></a>    <span class="dt">unsigned</span> <span class="dt">int</span> state_initialized:<span class="dv">1</span>;</span>
<span id="cb5-19"><a href="#cb5-19"></a>    <span class="co">//是否导出到sysfs</span></span>
<span id="cb5-20"><a href="#cb5-20"></a>    <span class="dt">unsigned</span> <span class="dt">int</span> state_in_sysfs:<span class="dv">1</span>;</span>
<span id="cb5-21"><a href="#cb5-21"></a>    <span class="co">//kobject添加</span></span>
<span id="cb5-22"><a href="#cb5-22"></a>    <span class="dt">unsigned</span> <span class="dt">int</span> state_add_uevent_sent:<span class="dv">1</span>;</span>
<span id="cb5-23"><a href="#cb5-23"></a>    <span class="co">//kobject移除</span></span>
<span id="cb5-24"><a href="#cb5-24"></a>    <span class="dt">unsigned</span> <span class="dt">int</span> state_remove_uevent_sent:<span class="dv">1</span>;</span>
<span id="cb5-25"><a href="#cb5-25"></a>};</span></code></pre></div>
<p>通过观察可以发现，kobject彼此之间保留了最小的共同特性子集而把操作类似的东西留给了ktype之类的结构。</p>
<h3 id="kset">kset</h3>
<p>kset是一种特殊的kobject，可以容纳多种类型的kobject（话说既然是ktype这个指针区别的话这个功能意义不大啊）</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">struct</span> kset {</span>
<span id="cb6-2"><a href="#cb6-2"></a>    <span class="co">//链表，表示kobject的集合</span></span>
<span id="cb6-3"><a href="#cb6-3"></a>    <span class="kw">struct</span> list_head list;</span>
<span id="cb6-4"><a href="#cb6-4"></a>    <span class="co">//链表的锁</span></span>
<span id="cb6-5"><a href="#cb6-5"></a>    spinlock_t list_lock;</span>
<span id="cb6-6"><a href="#cb6-6"></a>    <span class="co">//kset本身也是一个kobject，所以也有</span></span>
<span id="cb6-7"><a href="#cb6-7"></a>    <span class="kw">struct</span> kobject kobj;</span>
<span id="cb6-8"><a href="#cb6-8"></a>    <span class="co">//uevent相关的内容</span></span>
<span id="cb6-9"><a href="#cb6-9"></a>    <span class="kw">struct</span> kset_uevent_ops *uevent_ops;</span>
<span id="cb6-10"><a href="#cb6-10"></a>};</span></code></pre></div>
<h3 id="kobj_type">kobj_type</h3>
<p>kobj_type，给出了更进一步的kobject信息。</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1"></a></span>
<span id="cb7-2"><a href="#cb7-2"></a><span class="kw">struct</span> kobj_type {</span>
<span id="cb7-3"><a href="#cb7-3"></a>    <span class="co">//释放kobj时候的操作</span></span>
<span id="cb7-4"><a href="#cb7-4"></a>    <span class="dt">void</span> (*release)(<span class="kw">struct</span> kobject *kobj);</span>
<span id="cb7-5"><a href="#cb7-5"></a>    <span class="kw">struct</span> sysfs_ops *sysfs_ops;</span>
<span id="cb7-6"><a href="#cb7-6"></a>    <span class="kw">struct</span> attribute **default_attrs;</span>
<span id="cb7-7"><a href="#cb7-7"></a>};</span>
<span id="cb7-8"><a href="#cb7-8"></a></span>
<span id="cb7-9"><a href="#cb7-9"></a></span>
<span id="cb7-10"><a href="#cb7-10"></a><span class="kw">struct</span> sysfs_ops {</span>
<span id="cb7-11"><a href="#cb7-11"></a>    <span class="dt">ssize_t</span> (*show)(<span class="kw">struct</span> kobject *, <span class="kw">struct</span> attribute *,<span class="dt">char</span> *);</span>
<span id="cb7-12"><a href="#cb7-12"></a>    <span class="dt">ssize_t</span> (*store)(<span class="kw">struct</span> kobject *,<span class="kw">struct</span> attribute *,<span class="dt">const</span> <span class="dt">char</span> *, <span class="dt">size_t</span>);</span>
<span id="cb7-13"><a href="#cb7-13"></a>};</span>
<span id="cb7-14"><a href="#cb7-14"></a></span>
<span id="cb7-15"><a href="#cb7-15"></a></span>
<span id="cb7-16"><a href="#cb7-16"></a><span class="co">//暂时还没有看到有啥用</span></span>
<span id="cb7-17"><a href="#cb7-17"></a><span class="kw">struct</span> attribute {</span>
<span id="cb7-18"><a href="#cb7-18"></a>    <span class="dt">const</span> <span class="dt">char</span>      *name;</span>
<span id="cb7-19"><a href="#cb7-19"></a>    <span class="kw">struct</span> module       *owner;</span>
<span id="cb7-20"><a href="#cb7-20"></a>    mode_t          mode;</span>
<span id="cb7-21"><a href="#cb7-21"></a>};</span></code></pre></div>
<h3 id="kobject相关的函数">kobject相关的函数</h3>
<ol type="1">
<li><p>kobject_get、kobject_put函数增加和减少引用计数。</p></li>
<li><p>kobject_init:初始化对象。</p></li>
</ol>
<div class="sourceCode" id="cb8"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1"></a><span class="dt">void</span> kobject_init(<span class="kw">struct</span> kobject *kobj, <span class="kw">struct</span> kobj_type *ktype)</span>
<span id="cb8-2"><a href="#cb8-2"></a>{</span>
<span id="cb8-3"><a href="#cb8-3"></a>    <span class="dt">char</span> *err_str;</span>
<span id="cb8-4"><a href="#cb8-4"></a></span>
<span id="cb8-5"><a href="#cb8-5"></a>    <span class="cf">if</span> (!kobj) {</span>
<span id="cb8-6"><a href="#cb8-6"></a>        err_str = <span class="st">&quot;invalid kobject pointer!&quot;</span>;</span>
<span id="cb8-7"><a href="#cb8-7"></a>        <span class="cf">goto</span> error;</span>
<span id="cb8-8"><a href="#cb8-8"></a>    }</span>
<span id="cb8-9"><a href="#cb8-9"></a>    <span class="cf">if</span> (!ktype) {</span>
<span id="cb8-10"><a href="#cb8-10"></a>        err_str = <span class="st">&quot;must have a ktype to be initialized properly!</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb8-11"><a href="#cb8-11"></a>        <span class="cf">goto</span> error;</span>
<span id="cb8-12"><a href="#cb8-12"></a>    }</span>
<span id="cb8-13"><a href="#cb8-13"></a>    <span class="co">//不允许重复初始化</span></span>
<span id="cb8-14"><a href="#cb8-14"></a>    <span class="cf">if</span> (kobj-&gt;state_initialized) {</span>
<span id="cb8-15"><a href="#cb8-15"></a>        <span class="co">/* do not error out as sometimes we can recover */</span></span>
<span id="cb8-16"><a href="#cb8-16"></a>        printk(KERN_ERR <span class="st">&quot;kobject (%p): tried to init an initialized &quot;</span></span>
<span id="cb8-17"><a href="#cb8-17"></a>               <span class="st">&quot;object, something is seriously wrong.</span><span class="sc">\n</span><span class="st">&quot;</span>, kobj);</span>
<span id="cb8-18"><a href="#cb8-18"></a>        dump_stack();</span>
<span id="cb8-19"><a href="#cb8-19"></a>    }</span>
<span id="cb8-20"><a href="#cb8-20"></a>    </span>
<span id="cb8-21"><a href="#cb8-21"></a>    检查完毕后调用kobject_init_internal函数来初始化kobj</span>
<span id="cb8-22"><a href="#cb8-22"></a>    kobject_init_internal(kobj);</span>
<span id="cb8-23"><a href="#cb8-23"></a>    kobj-&gt;ktype = ktype;</span>
<span id="cb8-24"><a href="#cb8-24"></a>    <span class="cf">return</span>;</span>
<span id="cb8-25"><a href="#cb8-25"></a></span>
<span id="cb8-26"><a href="#cb8-26"></a>error:</span>
<span id="cb8-27"><a href="#cb8-27"></a>    printk(KERN_ERR <span class="st">&quot;kobject (%p): %s</span><span class="sc">\n</span><span class="st">&quot;</span>, kobj, err_str);</span>
<span id="cb8-28"><a href="#cb8-28"></a>    dump_stack();</span>
<span id="cb8-29"><a href="#cb8-29"></a>}</span>
<span id="cb8-30"><a href="#cb8-30"></a></span>
<span id="cb8-31"><a href="#cb8-31"></a></span>
<span id="cb8-32"><a href="#cb8-32"></a><span class="dt">static</span> <span class="dt">void</span> kobject_init_internal(<span class="kw">struct</span> kobject *kobj)</span>
<span id="cb8-33"><a href="#cb8-33"></a>{</span>
<span id="cb8-34"><a href="#cb8-34"></a>    <span class="cf">if</span> (!kobj)</span>
<span id="cb8-35"><a href="#cb8-35"></a>        <span class="cf">return</span>;</span>
<span id="cb8-36"><a href="#cb8-36"></a>    kref_init(&amp;kobj-&gt;kref);</span>
<span id="cb8-37"><a href="#cb8-37"></a>    INIT_LIST_HEAD(&amp;kobj-&gt;entry);</span>
<span id="cb8-38"><a href="#cb8-38"></a>    kobj-&gt;state_in_sysfs = <span class="dv">0</span>;</span>
<span id="cb8-39"><a href="#cb8-39"></a>    kobj-&gt;state_add_uevent_sent = <span class="dv">0</span>;</span>
<span id="cb8-40"><a href="#cb8-40"></a>    kobj-&gt;state_remove_uevent_sent = <span class="dv">0</span>;</span>
<span id="cb8-41"><a href="#cb8-41"></a>    <span class="co">//标明这个kobject已经初始化过了</span></span>
<span id="cb8-42"><a href="#cb8-42"></a>    kobj-&gt;state_initialized = <span class="dv">1</span>;</span>
<span id="cb8-43"><a href="#cb8-43"></a>}</span></code></pre></div>
<p>问题是kobject彼此之间建立联系的过程。</p>
<ol start="3" type="1">
<li>kobject_add函数。</li>
</ol>
<div class="sourceCode" id="cb9"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1"></a><span class="dt">int</span> kobject_add(<span class="kw">struct</span> kobject *kobj, <span class="kw">struct</span> kobject *parent,</span>
<span id="cb9-2"><a href="#cb9-2"></a>        <span class="dt">const</span> <span class="dt">char</span> *fmt, ...)</span>
<span id="cb9-3"><a href="#cb9-3"></a>{</span>
<span id="cb9-4"><a href="#cb9-4"></a>    <span class="dt">va_list</span> args;</span>
<span id="cb9-5"><a href="#cb9-5"></a>    <span class="dt">int</span> retval;</span>
<span id="cb9-6"><a href="#cb9-6"></a></span>
<span id="cb9-7"><a href="#cb9-7"></a>    <span class="cf">if</span> (!kobj)</span>
<span id="cb9-8"><a href="#cb9-8"></a>        <span class="cf">return</span> -EINVAL;</span>
<span id="cb9-9"><a href="#cb9-9"></a></span>
<span id="cb9-10"><a href="#cb9-10"></a>    <span class="cf">if</span> (!kobj-&gt;state_initialized) {</span>
<span id="cb9-11"><a href="#cb9-11"></a>        printk(KERN_ERR <span class="st">&quot;kobject &#39;%s&#39; (%p): tried to add an &quot;</span></span>
<span id="cb9-12"><a href="#cb9-12"></a>               <span class="st">&quot;uninitialized object, something is seriously wrong.</span><span class="sc">\n</span><span class="st">&quot;</span>,</span>
<span id="cb9-13"><a href="#cb9-13"></a>               kobject_name(kobj), kobj);</span>
<span id="cb9-14"><a href="#cb9-14"></a>        dump_stack();</span>
<span id="cb9-15"><a href="#cb9-15"></a>        <span class="cf">return</span> -EINVAL;</span>
<span id="cb9-16"><a href="#cb9-16"></a>    }</span>
<span id="cb9-17"><a href="#cb9-17"></a>    va_start(args, fmt);</span>
<span id="cb9-18"><a href="#cb9-18"></a>    <span class="co">//这个函数最终会设定名字（必须），加入kset（如果kobject设定了），导出对象到sysfs（vfs再说）</span></span>
<span id="cb9-19"><a href="#cb9-19"></a>    retval = kobject_add_varg(kobj, parent, fmt, args);</span>
<span id="cb9-20"><a href="#cb9-20"></a>    va_end(args);</span>
<span id="cb9-21"><a href="#cb9-21"></a></span>
<span id="cb9-22"><a href="#cb9-22"></a>    <span class="cf">return</span> retval;</span>
<span id="cb9-23"><a href="#cb9-23"></a>}</span></code></pre></div>
